/*
Copyright (c) 2007 Roger Braun

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.*/

#include "stdio.h"
#include "stdlib.h"
#include "SDL/SDL.h"
#include "SDL/SDL_endian.h"
#include "string.h"

#if SDL_BYTEORDER == SDL_LIL_ENDIAN
#define SWAP16(X)    (X)
#define SWAP32(X)    (X)
#else
#define SWAP16(X)    SDL_Swap16(X)
#define SWAP32(X)    SDL_Swap32(X)
#endif

//this file contains functions for reading .cob files. If you use it as "readcob filename.cob", it
//will print all filenames. If you specify a filename using "readcob filename.cob filename.txt", it
//will also print the content of the file.

typedef struct
{
	char filename[50];
	Uint32 size;
	Uint32 offset;
} cob_file;	

typedef struct
{
	int count;
	cob_file* table;
} cob_file_table;	

//This reads the cob file and returns the number of files in the file. 
//
int number_of_files(FILE *f)
{
	Uint32 buffer;
	fseek(f,0,SEEK_SET);
	fread(&buffer,sizeof(Uint32),1,f);	
	return SWAP32(buffer);
}	

//This prints all the filenames in the cobfile
void print_filenames(FILE *f)
{
	int filenumber,i;
	filenumber=number_of_files(f);
	char* filenames;
	//Every filename is saved as 50 chars
	filenames = malloc(50 * sizeof(char));
	for (i=0;i<filenumber;i++)
	{
		fread(filenames,sizeof(char),50,f);
		printf("%s\n",filenames);
	}
}	


Uint8* return_file(FILE *f, cob_file file)
{
	
	Uint8 *filecontent=malloc(sizeof(Uint8)*file.size);
	
	fseek(f,SWAP32(file.offset),SEEK_SET);
	fread(filecontent,sizeof(Uint8),file.size,f);
	
	return filecontent;
}	

Uint8* return_file_by_name(FILE *f, cob_file_table* files, char* filename)
{
	int i;
	for(i=0;i<files->count;i++)
	{
		if(strcmp(files->table[i].filename,filename)==0)
		{
			return return_file(f,files->table[i]);
		}
	}

}

int return_filesize_by_name(FILE *f, cob_file_table* files, char* filename)
{
	int i;
	for(i=0;i<files->count;i++)
	{
		if(strcmp(files->table[i].filename,filename)==0)
		{
			return files->table[i].size;
		}
	}

}

cob_file_table get_filetable(FILE *f)
{
	int files,i,temp,size;
	files = number_of_files(f);
	cob_file* table;
	table = (cob_file*) malloc(sizeof(cob_file)*files);
	
	//get the filesize of the .cob
	fseek(f, 0, SEEK_END);
	size = ftell(f);
	//go to the filenames
	fseek(f, 4, SEEK_SET);	
	
	for( i=0;i<files;i++)
	{
		fread(&(table[i].filename),sizeof(char),50,f);
	}
	for(i=0;i<files;i++)
	{
		fread(&(table[i].offset),sizeof(Uint32),1,f);	
	}
	for(i=0;i<files;i++)
	{
		if(i!=files-1)
		{
			table[i].size=SWAP32(table[i+1].offset)-SWAP32(table[i].offset);	
		}	
		else
		{
			table[i].size=size-SWAP32(table[i].offset);
		}
	
	}
	
	cob_file_table ctable;
	ctable.count=files;
	ctable.table=table;
	return ctable;
}

void print_cobfile_table(cob_file_table* files)
{
	int i;
	for (i=0;i<(*files).count;i++)
	{
		printf("Name: %s, offset: %x, size %u\n",files->table[i].filename, SWAP32(files->table[i].offset),files->table[i].size);
	}
}

void print_file(FILE *f, cob_file_table* files, char* filename)
{
	int i;
	for(i=0;i<files->count;i++)
	{
		if(strcmp(files->table[i].filename,filename)==0)
		{
			printf("%s",return_file(f,files->table[i]));
		}
	}

}

int main (int argc, char** argv)
{
	
	if (argc<2)
		printf("usage: readcob filename.cob");
	
	FILE *f = fopen(argv[1],"rb");
	
	
	printf("Number of files: %d\n",number_of_files(f));
	
	cob_file_table temp;
	temp=get_filetable(f);

	
	if(argc>2)
		print_file(f,&temp,argv[2]);
	else
		print_cobfile_table(&temp);
}
	
